import dayjs from 'dayjs'
import { find, flatMap, map, reduce } from 'lodash-es'

import { AppInfo, AppList, Dict } from '@/api/sys/model/appModel'
import { appStore, userStore } from '@/store/modules'

export function verificationToken() {
  // 1：安全可用；0：临近过期；-1：已过期

  if (userStore.getToken) {
    const { expiresIn = 0, tokenType } = userStore.authInfo ?? {}
    const diff = dayjs.unix(Number(expiresIn)).diff(undefined, 's')

    const expiration = userStore.authInfo?.expiration || 3600

    // 防止值过大，造成无限刷新token的问题
    // expiration = expiration > 23 * 3600 ? 3600 : expiresIn

    if (tokenType === 1) {
      return diff > +expiration ? 1 : diff > 0 ? 0 : -1
    } else {
      // 处理短效token
      return diff > 0 ? 1 : 0
    }
  } else {
    return -1
  }
}

export function getAppInfo(appCode: string | string[]) {
  if (!Array.isArray(appCode)) {
    appCode = [appCode]
  }
  const deepFind = (appCode: string, appList: AppList) => {
    const collection = flatMap(appList, ({ children = [], ...attrs }) => [
      attrs,
      ...children
    ])
    return find(collection, { appCode }) as AppInfo | undefined
  }

  let appInfo: AppInfo | undefined

  for (const code of appCode) {
    appInfo = deepFind(code, appInfo?.children ?? (appStore.appList as AppList))
  }

  return appInfo
}

export function getDictMappingByCode(
  code: string,
  findVal?: string | number
): Recordable
export function getDictMappingByCode(
  code: string,
  findVal: string | number
): string
export function getDictMappingByCode(
  code: string,
  findVal?: string | number
): string | Recordable {
  const mapping = reduce(
    appStore.dictionary?.[code],
    (prev, { dictKey, dictValue }) => ({
      ...prev,
      [dictKey]: dictValue
    }),
    {} as Recordable
  )

  return findVal !== undefined ? mapping[findVal] : mapping
}

export function getDictByCode<T extends 'original'>(
  code: string,
  type: T
): Record<string, Dict>
export function getDictByCode<T extends 'option'>(
  code: string,
  type: T
): LabelValueOption[]
export function getDictByCode(
  code: string,
  type: 'original' | 'option' = 'option'
): Record<string, Dict> | LabelValueOption[] {
  if (!appStore.dictionary) throw Error('Empty Dictionary')
  return type === 'original'
    ? (appStore.dictionary[code] as never)
    : (map(appStore.dictionary[code], ({ dictKey, dictValue }) => ({
        label: dictValue,
        value: +dictKey
      })) as never)
}
